/* HebSupport - Hebrew support for iPhone
 * Copyright (C) 2009 Aviram Segal (planB) Liraz Elias (Liraz)
*/

/* 
 * This program is free software; you can redistribute it and/or modify 
 * it under the terms of the GNU General Public License as published by 
 * the Free Software Foundation; either version 2 of the License, or 
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful, but 
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 
 * for more details.
 * 
 * You should have received a copy of the GNU General Public License along 
 * with this program; if not, write to the Free Software Foundation, Inc., 
 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */

#import <Foundation/Foundation.h>
#include "substrate.h"
#include "iVrit.h"
#include <alloca.h>
#include <unistd.h>
#include "ABMemberCell.h"

/* Declare ICU functions */
extern "C" void* ubidi_open();
extern "C" void ubidi_close(void*);
extern "C" void ubidi_setPara( void*, UChar*, int, UBiDiLevel, void*, UErrorCode* );
extern "C" int32_t ubidi_writeReordered( void*, UChar*, int, uint16_t, UErrorCode* );
extern "C" void ubidi_setReorderingMode(void*, UBiDiReorderingMode);
extern "C" UBiDiDirection ubidi_getDirection(void*);	

#define WEBCORE_FRAMEWORK "/System/Library/PrivateFrameworks/WebCore.framework/WebCore"
#define LIBICUCORE "/usr/lib/libicucore.dylib"

/* Bidi */
FloatSize (*__orig__drawText)(void* _this, void* context, TextRun& run, FloatPoint& point, int from, int to) = 0x0;

FloatSize __drawText(void* _this, void* context, TextRun& run, FloatPoint& point, int from, int to) {
    void *bidi;
    UErrorCode err = U_ZERO_ERROR;
    UBiDiLevel level = UBIDI_DEFAULT_LTR;

    bidi=ubidi_open();

    ubidi_setReorderingMode(bidi, UBIDI_REORDER_NUMBERS_SPECIAL);

    UChar* input = (UChar*)run.m_characters;
    int len = run.m_len;
    ubidi_setPara( bidi, input, len, level, NULL, &err );
    TextRun newRun = run;
    UChar* output = (UChar*)alloca(len * sizeof(UChar));
       
       
       if(!(run.m_rtl) && (ubidi_getDirection(bidi) != UBIDI_LTR)){
       ubidi_writeReordered( bidi, output, len, UBIDI_OUTPUT_REVERSE, &err );
               newRun.m_characters = output;
               newRun.m_rtl = true;
       }
 
    FloatSize ret =  __orig__drawText(_this, context, newRun, point, from, to);
    ubidi_close(bidi);
    return ret;
}

static id ABMembersController$sectionIndexTitlesForTableView(id self, SEL sel, id tableView) {
	NSInteger numOfSections = [self numberOfSectionsInTableView:tableView];
	NSMutableArray* mutableTitles = [NSMutableArray arrayWithCapacity:(numOfSections+1)];
	[mutableTitles insertObject:@"{search}" atIndex:0];
	NSUInteger i;
	for (i = 0; i < numOfSections; i++) {
		NSObject* obj = [self tableView:tableView titleForHeaderInSection:i];
		[mutableTitles insertObject:obj atIndex:(i+1)];
	}
	return mutableTitles;
}

static void ABMemberCell$drawContentInRectSelected(id self, SEL sel, CGRect rect, BOOL selected) {
	ABMemberCell* _self = (ABMemberCell*)self;
	NSArray* origNamePieces = _self->_namePieces;
	// If empty array we can stop
	if([origNamePieces count] == 0) {
		[self orig$drawContentInRect:rect selected:selected];
		return;
	}
	
	NSMutableArray* namePieces = [NSMutableArray arrayWithArray:origNamePieces];
	BOOL isHebrew = false;
	int origHighlightIndex = _self->_highlightIndex;
	
	NSString* firstName = [namePieces objectAtIndex:0];
	unichar firstNameFirstChar = [firstName characterAtIndex:0];
	if(0x0590 <= firstNameFirstChar && firstNameFirstChar <= 0x05FF) {
		isHebrew = true;
	}
	
	if(isHebrew) {
		int count = [namePieces count];
		if(count == 2) {
			[namePieces exchangeObjectAtIndex:0 withObjectAtIndex:1];
			_self->_highlightIndex = (origHighlightIndex+1)%2;
		} else if(count ==3) {
			// Person with prefix such as Doctor
			[namePieces exchangeObjectAtIndex:0 withObjectAtIndex:2];
			if(_self->_highlightIndex != 1) {
				_self->_highlightIndex = (origHighlightIndex+2)%4;
			}
		}
		_self->_namePieces = namePieces;
	}
	[self orig$drawContentInRect:rect selected:selected];
	_self->_highlightIndex = origHighlightIndex;
	_self->_namePieces = origNamePieces;
}

extern "C" void HSInitialize() {

	/* Hooks to WebCore/platform/graphics/Font.h - Font::drawText(GraphicsContext*, TextRun&, FloatPoint&, int from, int to); */
	/* BiDi supprt  */
	struct nlist nl[3];
	memset(nl, 0x0, sizeof(nl));
	nl[0].n_un.n_name = (char *) "__ZNK7WebCore4Font8drawTextEPNS_15GraphicsContextERKNS_7TextRunERKNS_10FloatPointEii";
	if(nlist(WEBCORE_FRAMEWORK, nl) == 0) {
		MSHookFunction((void *)nl[0].n_value, (void *)&__drawText, (void **)&__orig__drawText);
	} else {
		NSLog(@"Failed to hook drawText");
	}
  
	// We need this lib for Bidi
	if (dlopen(LIBICUCORE, RTLD_LAZY) == NULL) {
		NSLog(@"Failed to load icu");
	}
	MSHookMessage(objc_getClass("ABMembersController"), @selector(sectionIndexTitlesForTableView:), &ABMembersController$sectionIndexTitlesForTableView, "orig$");
	
	//Instead of ABModelRecord to support Cyntact in search
	MSHookMessage(objc_getClass("ABMemberCell"), @selector(drawContentInRect:selected:), &ABMemberCell$drawContentInRectSelected, "orig$");
	// Wait for saurik
	//MSHookMessage(objc_getClass("ABMemberCell"), @selector(initWithSize:member:), &ABMemberCell$initWithSizeMember, "orig$");
	/***************************************************************************************************************************/
}